﻿/*************************************************************************************
 * 文 件 名:   HK_RoamingCamPlayer
 * 
 * 描    述:   RoamingCam的主要控制脚本
 * 
 * 版    本：  V1.0
 * 创 建 者：  谭潇杰、京产肠饭
 * 创建时间：  2022/1/28
 * 链   接：  https://gitee.com/JingChanChangFan/hk_-unity-tools
*************************************************************************************/

using DG.Tweening;
using System.Collections;
using UnityEngine;
using UnityEngine.AI;
using QFramework;
using System;

namespace HKTools
{
    public class HK_RoamingCamPlayer : HK_RoamingCamController
    {
        IHK_RoamingCamSystem roamingCamSystem;

        [Header("摄像机旋转控制器："), SerializeField]
        HK_RoamingCamCtrl cameraCtrl;
        [Header("鸟瞰和三维的摄像机点位："), SerializeField]
        Transform overlookPos_TF;

        // 导航的角色组件
        NavMeshAgent agent;
        // 摄像机的Transform
        Camera childCam;

        //定义变量存放当前摄像机的透视和正视矩阵信息
        Matrix4x4 fromMatrix, toMatrix;
        //插值计算时应用的存储变量
        Matrix4x4 tempMatrix = new Matrix4x4();

        void Awake()
        {
            roamingCamSystem = this.GetSystem<IHK_RoamingCamSystem>();
            roamingCamSystem.InitRoamingCamSystem(false);

            agent = GetComponent<NavMeshAgent>();
            childCam = transform.GetComponentInChildren<Camera>();
        }

        void Start()
        {
            // 注册 切换 Roam Point 事件
            this.RegisterEvent<Event_SwitchRoamPoint>(OnSwitchRoamPoint)
                .UnRegisterWhenGameObjectDestroyed(gameObject);

            // 注册 切换到 BirdView Mode 事件
            this.RegisterEvent<Event_ChangeToBirdView>(OnChangeToBirdView)
                .UnRegisterWhenGameObjectDestroyed(gameObject);

            // 注册 切换到 ThreeD Mode 事件
            this.RegisterEvent<Event_ChangeToThreeDView>(OnChangeToThreeDView)
                .UnRegisterWhenGameObjectDestroyed(gameObject);

            // 注册 切换到 Roam Mode 事件
            this.RegisterEvent<Event_ChangeToRoamView>(OnChangeToRoamView)
                .UnRegisterWhenGameObjectDestroyed(gameObject);
        }

        // 切换 Roam Point
        void OnSwitchRoamPoint(Event_SwitchRoamPoint args)
        {
            childCam.transform.DOLocalRotate(Vector3.zero, 0.3f).SetEase(Ease.OutSine);
            transform.DOLookAt(new Vector3(args._point.transform.position.x, transform.position.y, args._point.transform.position.z), 0.3f)
                   .SetEase(Ease.OutSine)
                   .OnComplete(() =>
                   {
                       agent.enabled = true;
                       agent.SetDestination(args._point.transform.position);
                       StartCoroutine(JudgeAgentDistance_IE(args._point));
                   });
        }

        IEnumerator JudgeAgentDistance_IE(HK_Point point)
        {
            while (true)
            {
                yield return null;

                if (agent.remainingDistance <= 0.01f)
                {
                    agent.enabled = false;
                    SetPlayerLooAtByHK_Point(point);
                    break;
                }
            }
        }

        // 切换到 BirdView
        void OnChangeToBirdView(Event_ChangeToBirdView args)
        {
            // 将Camera从Player父物体中独立出来
            childCam.transform.SetParent(null);
            cameraCtrl.enabled = false;

            childCam.transform.DORotate(overlookPos_TF.localEulerAngles, 1f).SetDelay(0.3f);

            // 设置PC或移动端时，摄像机正交值的大小
            if (roamingCamSystem.IsMobile)
                childCam.orthographicSize = 28;
            else
                childCam.orthographicSize = 28;

            if (childCam.transform.position != overlookPos_TF.position)
            {
                childCam.transform.DOMove(overlookPos_TF.position, 1f)
                    .OnComplete(() =>
                    {
                        StartCoroutine(ChangeProjection_IE(() =>
                        {
                            cameraCtrl.enabled = true;
                            roamingCamSystem.IsCanRotCam.Value = true;
                        }));
                    });
            }
            else
            {
                StartCoroutine(ChangeProjection_IE(() =>
                {
                    cameraCtrl.enabled = true;
                    roamingCamSystem.IsCanRotCam.Value = true;
                }));
            }
        }

        // 切换到 ThreeDView
        void OnChangeToThreeDView(Event_ChangeToThreeDView args)
        {
            if (args._lastViewMode == ViewMode.BirdView)
            {
                DOTween.Sequence().OnStart(() =>
                {
                    childCam.transform.SetParent(null);
                    cameraCtrl.enabled = false;

                    StartCoroutine(ChangeProjection_IE());
                })
                .Append(childCam.transform.DOMove(overlookPos_TF.position, 0.5f))
                .AppendCallback(() =>
                {
                    cameraCtrl.enabled = true;
                    roamingCamSystem.IsCanRotCam.Value = true;
                });
            }

            if (args._lastViewMode == ViewMode.RoamView)
            {
                childCam.transform.DOMove(overlookPos_TF.position, 1f);
                childCam.transform.DORotate(overlookPos_TF.localEulerAngles, 1f)
                    .SetDelay(0.3f)
                    .OnComplete(() =>
                    {
                        cameraCtrl.enabled = true;
                        roamingCamSystem.IsCanRotCam.Value = true;
                    });
            }
        }

        // 切换到 RoamView
        void OnChangeToRoamView(Event_ChangeToRoamView args)
        {
            roamingCamSystem.IsCanRotCam.Value = false;
            cameraCtrl.enabled = false;

            if (args._lastViewMode == ViewMode.ThreeDView)
            {
                DOTween.Sequence()
                    .OnStart(() =>
                    {
                        transform.position = args._point.TargetPos;
                        childCam.transform.SetParent(transform);
                    })
                    .Append(childCam.transform.DOLocalMove(new Vector3(0, cameraCtrl.initCamPosY, 0), 1.2f))
                    .InsertCallback(1, () => SetPlayerLooAtByHK_Point(args._point));
            }

            if (args._lastViewMode == ViewMode.BirdView)
            {
                DOTween.Sequence()
                    .OnStart(() =>
                    {
                        StartCoroutine(ChangeProjection_IE());
                        transform.position = args._point.TargetPos;
                        childCam.transform.SetParent(transform);
                    })
                    .Append(childCam.transform.DOLocalMove(new Vector3(0, cameraCtrl.initCamPosY, 0), 1.2f))
                    .InsertCallback(1, () =>
                    {
                        SetPlayerLooAtByHK_Point(args._point);
                    });
            }
        }

        // 切换正交、透视摄像机投影方式，时间为0.3s
        IEnumerator ChangeProjection_IE(Action callback = null)
        {
            float currentT = 0f;

            while (currentT < 0.2f)  // 0.5s后切换正交或透视状态
            {
                yield return null;

                currentT += Time.deltaTime * 0.4f;

                if (childCam.orthographic) //如果当前摄像机为正视状态
                {
                    fromMatrix = childCam.projectionMatrix;

                    childCam.orthographic = false;
                    childCam.ResetProjectionMatrix();

                    toMatrix = childCam.projectionMatrix;

                    childCam.orthographic = true;
                    childCam.projectionMatrix = MatrixLerp(fromMatrix, toMatrix, currentT * currentT);
                }
                else //否则当前摄像机为透视状态
                {
                    fromMatrix = childCam.projectionMatrix;

                    childCam.orthographic = true;
                    childCam.ResetProjectionMatrix();

                    toMatrix = childCam.projectionMatrix;

                    childCam.orthographic = false;
                    childCam.projectionMatrix = MatrixLerp(fromMatrix, toMatrix, currentT);
                }
            }

            childCam.orthographic = !childCam.orthographic;
            childCam.ResetProjectionMatrix();

            callback?.Invoke();
        }

        Matrix4x4 MatrixLerp(Matrix4x4 from, Matrix4x4 to, float t)
        {
            t = Mathf.Clamp(t, 0.0f, 1.0f);

            tempMatrix.SetRow(0, Vector4.Lerp(from.GetRow(0), to.GetRow(0), t));
            tempMatrix.SetRow(1, Vector4.Lerp(from.GetRow(1), to.GetRow(1), t));
            tempMatrix.SetRow(2, Vector4.Lerp(from.GetRow(2), to.GetRow(2), t));
            tempMatrix.SetRow(3, Vector4.Lerp(from.GetRow(3), to.GetRow(3), t));
            return tempMatrix;
        }

        //通过HK_Point设置Player的朝向
        void SetPlayerLooAtByHK_Point(HK_Point hK_Point)
        {
            switch (hK_Point.lookAtType)
            {
                case LookAtType.Diffuse:

                    if (childCam.transform.localEulerAngles != Vector3.zero)
                    {
                        childCam.transform.DOLocalRotate(Vector3.zero, 0.35f)
                                  .OnComplete(() =>
                                  {
                                      cameraCtrl.mouseLook.Init(transform, childCam.transform);
                                      cameraCtrl.enabled = true;
                                      roamingCamSystem.IsCanRotCam.Value = true;
                                  });
                    }
                    else
                    {
                        cameraCtrl.mouseLook.Init(transform, childCam.transform);
                        cameraCtrl.enabled = true;
                        roamingCamSystem.IsCanRotCam.Value = true;
                    }
                    break;

                case LookAtType.ByQuaternion:
                    Vector3 targetEuler = hK_Point.lookAtRot.eulerAngles;

                    childCam.transform.DORotateQuaternion(Quaternion.Euler(new Vector3(targetEuler.x, targetEuler.y, 0)), 1f);

                    transform.DORotateQuaternion(Quaternion.Euler(new Vector3(transform.eulerAngles.x, targetEuler.y, transform.eulerAngles.z)), 1f)
                        .OnComplete(() =>
                        {
                            cameraCtrl.mouseLook.Init(transform, childCam.transform);
                            cameraCtrl.enabled = true;
                            roamingCamSystem.IsCanRotCam.Value = true;
                        });
                    break;

                case LookAtType.ByTarget:
                    Vector3 newPos = hK_Point.lookAtPos;
                    transform.DOLookAt(new Vector3(newPos.x, transform.position.y, newPos.z), 1f);
                    cameraCtrl.transform.DOLookAt(newPos, 1f)
                             .OnComplete(() =>
                             {
                                 Vector3 camTargetEuler = new Vector3(cameraCtrl.transform.localEulerAngles.x, 0, 0);

                                 if (camTargetEuler.x > 180)
                                     camTargetEuler.x -= 360;
                                 else if (camTargetEuler.x < -180)
                                     camTargetEuler.x += 360;

                                 cameraCtrl.transform.DOLocalRotateQuaternion(Quaternion.Euler(camTargetEuler), 1f)
                                 .OnComplete(() =>
                                 {
                                     cameraCtrl.mouseLook.Init(transform, childCam.transform);
                                     cameraCtrl.enabled = true;
                                     roamingCamSystem.IsCanRotCam.Value = true;
                                 });
                             });
                    break;
            }
        }
    }
}